package p.ithorns.tools.serializer;

import org.nustaq.serialization.*;
import org.nustaq.serialization.coders.FSTStreamDecoder;
import org.nustaq.serialization.coders.FSTStreamEncoder;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.io.IOException;
import java.lang.reflect.Field;
import java.util.Arrays;

/**
 * FstInstanceHolder
 *
 * @author ithorns
 * @version 1.0.0
 * @date 2022/12/10 15:08
 */
public class FstSerializer {

    private final static Logger log = LoggerFactory.getLogger(FstSerializer.class);

    public static byte[] serialize(Object obj) {
        return InstanceHolder.INSTANCE.asByteArray(obj);
    }

    public static Object deserialize(byte[] bytes) {
        return InstanceHolder.INSTANCE.asObject(bytes);
    }

    /**
     * 将FST的十六进制字符串转换为字节数组
     *
     * FST的2进制结构：[Header|类名长度|类名String|字段1类型(1Byte) | [长度] | 内容|字段2类型(1Byte) | [长度] | 内容|…]
     *
     * @param hexStr fst-hex 如redis序列化后的字符串
     * @return byte[]
     */
    public static byte[] fstHexToBytes(String hexStr) {
        // 重新构建原始字符串，但将十六进制序列替换为对应的字节
        boolean inHex = false;
        int length = hexStr.length();
        byte[] result = new byte[length];
        int resultIndex = 0;
        StringBuilder tempHex = new StringBuilder();
        for (int i = 0; i < length; i++) {
            char c = hexStr.charAt(i);
            if (c == '\\' && i + 2 < length && hexStr.charAt(i + 1) == 'x') {
                if (tempHex.length() > 0) {
                    // 处理前一个不完整的十六进制序列
                    try {
                        result[resultIndex++] = (byte) Integer.parseInt(tempHex.toString(), 16);
                    } catch (NumberFormatException e) {
                        throw new IllegalArgumentException("Invalid hex sequence: " + tempHex, e);
                    }
                    tempHex.setLength(0);
                }
                i++; // 跳过 '\'
                inHex = true;
                continue;
            }

            if (inHex) {
                tempHex.append(c);
                if (tempHex.length() == 2) {
                    try {
                        result[resultIndex++] = (byte) Integer.parseInt(tempHex.toString(), 16);
                    } catch (NumberFormatException e) {
                        throw new IllegalArgumentException("Invalid hex sequence: " + tempHex, e);
                    }
                    tempHex.setLength(0);
                    inHex = false;
                }
            } else {
                result[resultIndex++] = (byte) c;
            }
        }

        // 处理可能遗留的不完整十六进制序列
        if (inHex && tempHex.length() > 0) {
            try {
                result[resultIndex++] = (byte) Integer.parseInt(tempHex.toString(), 16);
            } catch (NumberFormatException e) {
                throw new IllegalArgumentException("Invalid hex sequence: " + tempHex, e);
            }
        }

        // 返回实际使用的字节数组部分
        return Arrays.copyOf(result, resultIndex);
    }

    public static void init() {
        InstanceHolder.INSTANCE.setName("FstSerializer");
    }

    /**
     * 单例
     */
    static class InstanceHolder {
        private static final FSTConfiguration INSTANCE = FSTConfiguration.createDefaultConfiguration();

        static {
            INSTANCE.setStreamCoderFactory(new FSTDefaultStreamCoderFactory(INSTANCE));
            INSTANCE.registerSerializer(String.class, new IgnoreSerializer(), true);
        }

    }

    static class FSTDefaultStreamCoderFactory implements FSTConfiguration.StreamCoderFactory {
        // 单例的生成工厂,
        // 并且让FSTStreamDecoder.chBufS FSTStreamDecoder.ascStringCache为空

        static ThreadLocal input = new ThreadLocal();
        static ThreadLocal output = new ThreadLocal();
        private final FSTConfiguration fstConfiguration;
        Field chBufField;
        Field ascStringCacheField;

        {
            try {
                chBufField = FSTStreamDecoder.class.getDeclaredField("chBufS");
                ascStringCacheField = FSTStreamDecoder.class.getDeclaredField("ascStringCache");
            } catch (Exception e) {
                throw new IllegalStateException(e);
            }
            ascStringCacheField.setAccessible(true);
            chBufField.setAccessible(true);
        }

        FSTDefaultStreamCoderFactory(FSTConfiguration fstConfiguration) {
            this.fstConfiguration = fstConfiguration;
        }

        @Override
        public FSTEncoder createStreamEncoder() {
            return new FSTStreamEncoder(fstConfiguration);
        }

        @Override
        public FSTDecoder createStreamDecoder() {
            return new FSTStreamDecoder(fstConfiguration) {
                @Override
                public String readStringUTF() throws IOException {
                    try {
                        String res = super.readStringUTF();
                        chBufField.set(this, null);// xField.set(FSTStreamDecoder obj, Object value) 把FSTStreamDecoder对象的xField设置为value
                        return res;
                    } catch (Exception e) {
                        throw new IOException(e);
                    }
                }

                @Override
                public String readStringAsc() throws IOException {
                    try {
                        String res = super.readStringAsc();
                        ascStringCacheField.set(this, null);
                        return res;
                    } catch (Exception e) {
                        throw new IOException(e);
                    }
                }
            };
        }

        @Override
        public ThreadLocal getInput() {
            return input;
        }

        @Override
        public ThreadLocal getOutput() {
            return output;
        }
    }


    static class IgnoreSerializer  extends FSTBasicObjectSerializer {

        @Override
        public boolean willHandleClass(Class clazz) {
            return clazz == String.class;
        }

        @Override
        public void writeObject(FSTObjectOutput out, Object toWrite, FSTClazzInfo clzInfo,
                                FSTClazzInfo.FSTFieldInfo referencedBy, int streamPosition) throws IOException {
            log.info("=========> 序列化String类型数据：{}", toWrite);
        }

        @Override
        public void readObject(FSTObjectInput in, Object toRead,
                               FSTClazzInfo clzInfo, FSTClazzInfo.FSTFieldInfo referencedBy) throws Exception {
            log.info("=========> 反序列化String类型数据：{}", toRead);
        }

        @Override
        public Object instantiate(Class objectClass, FSTObjectInput in,
                                  FSTClazzInfo serializationInfo,
                                  FSTClazzInfo.FSTFieldInfo referencee,
                                  int streamPosition) throws Exception {
            return null;
        }
    }

}